package org.ns.summer.mvc.dynamicexec;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态执行, 执行一个方法, 参数可以任意扩展
 * 
 * @author 张星宇
 * @version 1.0
 *
 */
public class DynamicExecute {
	/**
	 * 自动参数模版
	 * 
	 */
	private ExecParamTemplate execParamTemplate;
	private ExecParamTemplate defaultParamTemplate = new DefualtParamTemplate();
	/**
	 * 默认类型参数
	 * 
	 */
	private Map<Class<?>, Object> defaultClassPatam = new HashMap<Class<?>, Object>();

	/**
	 * 默认的执行
	 * 
	 */
	public DynamicExecute() {
	}

	/**
	 * 执行参数配置的模版
	 * 
	 * @param execParamTemplate
	 */
	public DynamicExecute(ExecParamTemplate execParamTemplate) {
		super();
		this.execParamTemplate = execParamTemplate;
	}

	/**
	 * 添加默认的类型参数
	 * 
	 * @param type
	 * @param value
	 */
	public void put(Class<?> type, Object value) {
		defaultClassPatam.put(type, value);
	}

	public void put(Object value) {
		if (value != null) {
			defaultClassPatam.put(value.getClass(), value);
		}
	}

	/**
	 * 获得这个类型的值
	 * 
	 * @param type
	 * @return
	 */
	public Object get(Class<?> type) {
		return get(type, null);
	}

	/**
	 * 获得这个类型的值,如果值 null 则使用默认值
	 * 
	 * @param type
	 * @param def
	 * @return
	 */
	public Object get(Class<?> type, Object def) {
		Object value = defaultClassPatam.get(type);
		if (value == null) {
			return def;
		}
		return value;
	}

	public ExecParamTemplate getAutoParamTemplate() {
		return execParamTemplate;
	}

	private final static Object EM_PARAMS[] = {};

	/**
	 * 获得参数对象
	 * 
	 * @param invokeObj
	 * @return
	 */
	public Object[] getParams(Executable invokeObj) throws Exception{
		Class<?> paramTypes[] = invokeObj.getParameterTypes();
		if (paramTypes == null || paramTypes.length == 0) {
			return EM_PARAMS;
		}
		Annotation[] invokeObjAnns = invokeObj.getAnnotations();
		Map<Class<? extends Annotation>, Annotation> invokeAnns = getAnnMap(invokeObjAnns);
		Object params[] = new Object[paramTypes.length];
		Annotation[][] paramAnnss = invokeObj.getParameterAnnotations();
		for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
			Map<Class<? extends Annotation>, Annotation> paramAnns = getAnnMap(paramAnnss[paramIndex]);
			Class<?> paramType = paramTypes[paramIndex];
			ExecParamInfo autoParamInfo = new ExecParamInfo(invokeObj, paramAnnss[paramIndex], invokeAnns, paramAnns, paramType, this,
					paramIndex);
			Object value = null;
			if (execParamTemplate != null && execParamTemplate.preHandle(autoParamInfo)) {
				value = execParamTemplate.paramLoad(autoParamInfo);
			}
			if (value == null) {
				value = defaultParamTemplate.paramLoad(autoParamInfo);
			}
			params[paramIndex] = value;
		}

		return params;
	}

	/**
	 * 执行方法
	 * 
	 * @param obj
	 * @param method
	 * @return
	 * @throws Throwable
	 */
	public Object invoke(Object obj, Method method) throws Throwable {
		if (method == null) {
			return null;
		}
		method.setAccessible(true);
		Object params[] = getParams(method);
		return method.invoke(obj, params);
	}

	/**
	 * 通过指定构造创建类对象
	 * 
	 * @param obj
	 * @param constructor
	 * @return
	 * @throws Throwable
	 */
	public <T> T newInstance(Object obj, Constructor<T> constructor) throws Throwable {
		if (constructor == null) {
			return null;
		}
		constructor.setAccessible(true);
		Object params[] = getParams(constructor);
		return constructor.newInstance(params);
	}

	/**
	 * 通过指定构造创建类对象, 发生异常返回 null
	 * 
	 * @param obj
	 * @param constructor
	 * @return
	 */
	public <T> T newInstanceNoThrow(Object obj, Constructor<T> constructor) {
		try {
			return newInstance(obj, constructor);
		} catch (Throwable e) {
			e.printStackTrace();
			return null;
		}
	}

	private Map<Class<? extends Annotation>, Annotation> getAnnMap(Annotation[] anns) {
		Map<Class<? extends Annotation>, Annotation> annMap = new HashMap<>();
		if (anns == null || anns.length == 0) {
			return annMap;
		}
		for (Annotation ann : anns) {
			annMap.put(ann.annotationType(), ann);
		}
		return annMap;
	}
}
